package tss.layer;

import java.io.*;
import java.net.*;

import tss.*;

/**
 * A reliable multicast layer that uses UDP multicast to multicast
 * messages among processes
 * 
 * The following additional properties are required:
 * 
 * "multicast.port" : an integer port number designating the port on which this process
 *                    should create a multicast socket
 * "multicast.address" : a string designating the multicast IP address for the group
 *                       that this process should join
 * 
 * @author Klaus Marius Hansen, klaus.m.hansen@daimi.au.dk
 *
 */
public class MulticastLayer extends Layer {
	MulticastSocket socket;
	InetAddress group;
	int port;
	
	public void setProperties(String ... properties) {
		super.setProperties(properties);
		try {
			port = new Integer(getProperty("multicast.port"));
			socket = new MulticastSocket(port);
			group = InetAddress.getByName(getProperty("multicast.address"));
			socket.joinGroup(group);
			startReceiving();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Start a Thread that listens for incoming messages on socket
	 */
	private void startReceiving() {
		new Thread() {
			public void run() {
				while (true) {
					try {
						byte[] buffer = new byte[1024];
						DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
						socket.receive(packet);
						up(Message.fromByteArray(buffer));
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
	}
	
	public void down(Message message) throws IOException {
		message.pushHeader(new Integer(getProperty("process.id")));
		byte[] buffer = message.toByteArray();
		socket.send(new DatagramPacket(buffer, buffer.length, group, port));
	}
	
	public void up(Message message) {
		if (id != (Integer)message.popHeader()) {
			super.up(message);
		}
	}
}
